﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;

namespace WF.Model
{
    /// <summary>
    /// 实体基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [Serializable]
    public abstract class EntityBase<T> : INotifyPropertyChanged where T : class,INotifyPropertyChanging, INotifyPropertyChanged, new()
    {
        #region static
        //辅助对象，用于同步

        private static Object _lockObject = new object();

        //缓存LINQ实体PropertyInfo
        private static PropertyInfo[] dbEntityPropertyInfos;
        private static List<string> dbEntityKeys;
        #endregion

        #region private 属性

        //对应的LINQ实体对象
        private T _dbEntity;

        //存放每个属性是否已经修改

        private System.Collections.Generic.Dictionary<string, bool> _changeMark;
        #endregion

        #region protected 属性

        protected T DbEntity
        {
            get { return _dbEntity; }
            set { _dbEntity = value; this.SendPropertyChanged("DbEntity"); }
        }
        #endregion

        #region abstract
        /// <summary>
        /// ID  abstract属性,需要由子类实现
        /// </summary>
        public abstract string ID { get; set; }
        public abstract string DisplayName { get; }
        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数

        /// </summary>
        public EntityBase()
        {
            //初始化信息

            if (dbEntityPropertyInfos == null)
            {
                //锁定，避免并发时重复初始化

                lock (_lockObject)
                {
                    if (dbEntityPropertyInfos == null)
                    {
                        InitEntityPropertyInfos();
                    }
                }
            }
            _dbEntity = new T();
            _changeMark = new Dictionary<string, bool>();

            //注册属性更改事件

            this.PropertyChanged += new PropertyChangedEventHandler(_dbEntity_PropertyChanged);
            //_dbEntity.PropertyChanged += new PropertyChangedEventHandler(_dbEntity_PropertyChanged);
        }

        //
        void _dbEntity_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //当属性发生了改变,则记录下来

            _changeMark[e.PropertyName] = true;
        }

        /// <summary>
        /// 构造函数

        /// </summary>
        /// <param name="dbEntity"></param>
        public EntityBase(T dbEntity)
        {
            //初始化信息

            if (dbEntityPropertyInfos == null)
            {
                //锁定，避免并发时重复初始化

                lock (_lockObject)
                {
                    if (dbEntityPropertyInfos == null)
                    {
                        InitEntityPropertyInfos();
                    }
                }
            }
            if (null == dbEntity)
            {
                _dbEntity = new T();
            }
            else
            {
                _dbEntity = dbEntity;
            }
            _changeMark = new Dictionary<string, bool>();
        }
        #endregion

        #region 事件
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void SendPropertyChanged(String propertyName)
        {
            if ((this.PropertyChanged != null))
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region Public 方法
        /// <summary>
        /// 返回LINQ实体
        /// </summary>
        /// <returns></returns>
        public T DBEntity
        {
            get
            {
                return _dbEntity;
            }
            //set
            //{
            //}                   
        }

        /// <summary>
        /// 更新LINQ实体
        /// </summary>
        /// <param name="dbEntity"></param>
        public virtual void UpdateDBEntity(T dbEntity)
        {
            foreach (PropertyInfo propertyInfo in dbEntityPropertyInfos)
            {
                if (dbEntityKeys.Contains(propertyInfo.Name))
                {
                    //if (propertyInfo.GetValue(_dbEntity, null) != propertyInfo.GetValue(dbEntity, null) )
                    //{
                    //    throw new Exception(string.Format("更新实体对象{0}时出现错误，主键值不相等"));
                    //}
                }

                if (IsPropertyChange(propertyInfo.Name))
                {
                    propertyInfo.SetValue(dbEntity, propertyInfo.GetValue(_dbEntity, null), null);
                }
            }
        }

        public void CopyFrom(EntityBase<T> obj)
        {
            this.DbEntity = obj.DbEntity;
        }

        public void CopyFrom(T obj)
        {
            this.DbEntity = obj;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="PropertyName"></param>
        /// <returns></returns>
        public object GetPropertyValue(string PropertyName)
        {
            object ret = null;
            foreach (PropertyInfo propertyInfo in dbEntityPropertyInfos)
            {
                if (propertyInfo.Name == PropertyName)
                {
                    ret = propertyInfo.GetValue(_dbEntity, null);
                    break;
                }
            }
            return ret;
        }

        #endregion

        #region protected 方法
        /// <summary>
        /// 标记该属性已经修改

        /// </summary>
        /// <param name="PropertyName">属性名</param>
        protected void MarkPropertyChange(string PropertyName)
        {
            _changeMark[PropertyName] = true;
        }

        /// <summary>
        /// 检查该属性是否已经修改

        /// </summary>
        /// <param name="PropertyName"></param>
        /// <returns></returns>
        protected bool IsPropertyChange(string PropertyName)
        {
            if (_changeMark.ContainsKey(PropertyName))
            {
                return _changeMark[PropertyName];
            }
            else
            {
                return false;
            }
        }

        #endregion

        #region Private 方法
        private void InitEntityPropertyInfos()
        {
            Type DBEntityType = typeof(T);
            dbEntityPropertyInfos = DBEntityType.GetProperties();
            dbEntityKeys = new List<string>();
            foreach (PropertyInfo propertyInfo in dbEntityPropertyInfos)
            {
                System.Attribute dbEntityPropertyAttribute = System.Attribute.GetCustomAttribute(propertyInfo, typeof(System.Data.Linq.Mapping.ColumnAttribute));
                if ((null != dbEntityPropertyAttribute) && (((System.Data.Linq.Mapping.ColumnAttribute)dbEntityPropertyAttribute).IsPrimaryKey))
                {
                    dbEntityKeys.Add(propertyInfo.Name);
                }
            }


        }
        #endregion

    }
}
